package com.example.win.android_banduyujia.ui.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.LruCache;
import android.widget.ImageView;

import com.example.win.android_banduyujia.BanDuApp;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;

/**
 * Created by Win on 2015/8/11.
 */
public class ImageLoader {

    private static final int IMAGE_CALL_BACK_HANDLER_CODE = 0;
    private static final int IMAGE_LOAD_RUNNING_THREAD_MAX_NUMBER= 2;
    private static final int IMAGE_VIEW_SIZE = 10;
    private static final int MEM_MAX_SIZE = 4 * 1024 * 1024;
    private LruCache<String, Bitmap>  mMemoryCache = null; // 1级缓存
    private HashMap<String, SoftReference<Bitmap>>  mImageCache; // 2级缓存
    private HashMap<String, List<PhotoToLoad>>  mLoadingImage;
    private List<Thread>  mRunningThread;
    private List<Thread>  mWaitingThread;
    private FileCache  fileCache;

    private static ImageLoader mImageLoader;

    public static ImageLoader getInstance() {
        if(mImageLoader == null){
            mImageLoader = new ImageLoader(BanDuApp.getContext());
        }
        return mImageLoader;
    }

    public ImageLoader(Context context) {
       mMemoryCache = new LruCache<String, Bitmap>(MEM_MAX_SIZE){
           @Override
           protected int sizeOf(String key, Bitmap value) {
               return value.getRowBytes() * value.getHeight();
           }

           @Override
           protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
               putBitmapIntoImageCache(key, oldValue);
           }
       };
        mImageCache = new HashMap<String, SoftReference<Bitmap>>();
        mLoadingImage = new HashMap<String, List<PhotoToLoad>>();
        mRunningThread = new ArrayList<Thread>();
        mWaitingThread = new ArrayList<Thread>();
        fileCache = new FileCache(context);
    }

    public void downloadImage(String url, ImageView imageView) {
        PhotoToLoad  load = new PhotoToLoad(url, imageView);
        getBitmap(url, load);
    }

    public Bitmap getImage(String url) {
        Bitmap  bitmap = mMemoryCache.get(url);
        if(bitmap !=null && !bitmap.isRecycled()){

            return bitmap;
        }else{
            mMemoryCache.remove(url);
        }

        SoftReference<Bitmap>  softReference = mImageCache.get(url);
        if(softReference !=null){
            bitmap = softReference.get();
        }
        if(bitmap !=null){

            return bitmap;
        }else{
            mMemoryCache.remove(url);
        }
        return null;
    }

    private void getBitmap(final String url, final PhotoToLoad imageView) {
        if(url == null || imageView == null){
            return;
        }
        final Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what){
                    case IMAGE_CALL_BACK_HANDLER_CODE:
                        Drawable cachedImage = null;
                        Object  obj = msg.obj;
                        if(obj != null && obj instanceof Drawable){
                            cachedImage = (Drawable) obj;
                        }
                        if(cachedImage != null){
                            List<PhotoToLoad>  imageViewList = mLoadingImage.get(url);
                            if(imageViewList !=null){
                                for(PhotoToLoad image : imageViewList){
                                    if(image.url !=null && image.url.equals(url)){
                                        image.imageView.setImageDrawable(cachedImage);
                                    }
                                }
                            }
                        }
                        mLoadingImage.remove(url);
                        break;
                }
            }
        };
        // 从内存中获取
        synchronized (mMemoryCache){
            Bitmap  bitmap = mMemoryCache.get(url);
            if(bitmap !=null && !bitmap.isRecycled()){

                imageView.imageView.setImageBitmap(bitmap);
                return;
            }else{
                mMemoryCache.remove(url);
            }
            SoftReference<Bitmap>  softReference = mImageCache.get(url);
            if(softReference !=null){
                bitmap = softReference.get();
            }
            if(bitmap != null){

                imageView.imageView.setImageBitmap(bitmap);
                return;
            }else{
                mImageCache.remove(url);
            }
        }
        try{
            if(!mLoadingImage.containsKey(url)){
                Thread  thread = new Thread(){
                    @Override
                    public void run() {
                        Drawable  drawable = null;
                        if(url != null || !"".equals(url)){
                            Bitmap bitmap = imageDownload(url);
                            if(bitmap != null){
                                mMemoryCache.put(url, bitmap);
                                drawable = new BitmapDrawable(bitmap);
                            }
                        }
                        Message  message = handler.obtainMessage(IMAGE_CALL_BACK_HANDLER_CODE, drawable);
                        handler.sendMessage(message);
                        mRunningThread.remove(this);
                        synchronized (mWaitingThread){
                            if(!mWaitingThread.isEmpty() && mRunningThread.size() < IMAGE_LOAD_RUNNING_THREAD_MAX_NUMBER){
                                Thread unrunThread = mWaitingThread.remove(0);
                                mRunningThread.add(unrunThread);
                                unrunThread.start();
                            }
                        }
                    }
                };
                addLoadingImage(url, imageView.imageView);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void putBitmapIntoMemCache(String url, Bitmap bitmap) {
         mMemoryCache.put(url, bitmap);
    }

    private void putBitmapIntoImageCache(String key, Bitmap oldValue) {
        SoftReference<Bitmap>  softReference = mImageCache.get(key);
        if(softReference  !=null){
            return;
        }
        mImageCache.put(key, new SoftReference<Bitmap>(oldValue));
    }

    private void addLoadingImage(String url, ImageView imageView) {
        List<PhotoToLoad>  images = mLoadingImage.get(url);
        PhotoToLoad load = new PhotoToLoad(url, imageView);
        if(images == null){
            images = new ArrayList<PhotoToLoad>();
            images.add(load);
        }else{
            if(images.size() > IMAGE_VIEW_SIZE){
                images.remove(0);
            }
            images.add(load);
        }
        mLoadingImage.put(url, images);
    }

    private Bitmap imageDownload(String url) {
        File  f = fileCache.getFile(url);
        Bitmap  bitmap = null;
        if(f != null && f.exists()){
            bitmap = BitmapFactory.decodeFile(f.getPath());
        }
        if(bitmap != null){

            return bitmap;
        }

        InputStream  is = null;
        try {
            URL  url1 = new URL(url);

            HttpURLConnection  conn = (HttpURLConnection) url1.openConnection();
            conn.setConnectTimeout(30000);
            conn.setReadTimeout(30000);
            conn.setInstanceFollowRedirects(true);
            is = conn.getInputStream();
            String  status = Environment.getExternalStorageState();
            if(!status.equals(Environment.MEDIA_MOUNTED)){
                bitmap = BitmapFactory.decodeStream(is);
            }else{
                byte[]  data = null;
                ByteArrayOutputStream   os = null;
                os = new ByteArrayOutputStream();
                byte[]  buffer = new byte[1024];
                int  len = 0;
                while ((len = is.read(buffer)) != -1){
                    os.write(buffer, 0, len);
                }
                data = os.toByteArray();
                if(data != null){
                    bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                }
                os.close();
                if(bitmap != null){
                    saveFile(bitmap, f.getPath());

                    return bitmap;
                }
            }
            return bitmap;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                if(is != null){
                    is.close();
                    is = null;
                }
            }catch (IOException e1){

            }
        }
        return null;
    }

    private boolean saveFile(Bitmap bm, String fileName) {
        File  exportDirPath = new File(fileName);
        if(!exportDirPath.exists()){
            try{
               exportDirPath.createNewFile();
            }catch (IOException e){
                e.printStackTrace();
                return false;
            }
        }
        BufferedOutputStream  bos;
        try{
           bos = new BufferedOutputStream(new FileOutputStream(exportDirPath));
            bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
            bos.flush();
            bos.close();
        }catch (Exception e){
            return false;
        }
        return  true;
    }

    public void clearCache(){
        if(mMemoryCache != null){
            mMemoryCache.evictAll();
        }
    }

    public void init(ImageLoaderConfiguration config) {

    }

    // 用于标记
    public class  PhotoToLoad{
        public String url;
        public ImageView  imageView;
        public PhotoToLoad(String u, ImageView i){
            url = u;
            imageView = i;
        }
    }
}
